package com.google.wavesurferrobot.textmining;

/*
*************************************************************************************************
* File:         MutualInfo.java                                                                 *
* Usage:        MutualInfo implements the MI measure                                            *
*************************************************************************************************
* IDE/Compiler: For the development needs we used NetBeans 5.0 and JRE 1.5.0_06 on WinXP Home   *
*************************************************************************************************
* License:      (LGPL) GNU Lesser General Public License                                        *
*               http://www.opensource.org/licenses/lgpl-license.php                             *
*************************************************************************************************
*         Originally written by George Tsatsaros (gbt@aueb.gr)                                  *      
*               Author         :  Panayiotis Papadopoulos (3010010)                             *
*               Website        :  http://dias.aueb.gr/~p3010010/                                *
*               E-mail         :  papado@freemail.gr                                            *
*                                 p3010010@dias.aueb.gr                                         *
*               MSN messenger  :  pap5@hotmail.com                                              *
*               Skype          :  papOnSlayer                                                   *
*                                                                                               *
* Contact:  Feel free to contact with me for any question/suggestion using the email(s) above   *
*************************************************************************************************
*/

import java.lang.Math.*;
import java.util.Enumeration;
import java.util.Hashtable;


public class MutualInfo
{
    private String token;

    private double mutInfo;


    public MutualInfo(String token, int documentsNum, Hashtable category)
    {
        this.token = token;
        computeMutualInfo(documentsNum, category);
    }

    public double getMutualInfo()
    {
        return mutInfo;
    }

    //MI(t) = Sum(Pr(Ci) * MI(t,Ci))
    private void computeMutualInfo(int documentsNum, Hashtable category)
    {
        mutInfo = 0;

        for (Enumeration e = category.elements(); e.hasMoreElements(); )
        {
            Category catObj = (Category) e.nextElement();
            double probC = catObj.getCategoryProbability();

            MI miObj = new MI(token, catObj, category, documentsNum);
            mutInfo += probC * miObj.getMI();
        }
    }


//-------------- inner class

    class MI
    {
        private String token;

        private int A;    //Number of documents in c containing t
        private int B;    //Number of documents not in c, containing t
        private int C;    //Number of documents in c not containing t
        private int N;    //Number of documents

        private double mutInf;


        public MI(String token, Category thisCatObj, Hashtable category, int documentsNum)
        {
            this.token = token;
            this.N = documentsNum;
            computeMI(thisCatObj, category);
        }

        public double getMI()
        {
            return mutInf;
        }

        //MI(t,Ci) = lg( (A*N) / ((A+C)*(A+B)) )
        private void computeMI(Category thisCatObj, Hashtable category)
        {
            computeA_C_B(thisCatObj, category);

            double tmp = ((double) (A * N)) / ((double) ((A + C) * (A + B)));

            mutInf = lg(tmp);
        }

        //A = Number of documents in thisCatObj, containing token
        //C = Number of documents in thisCatObj, not containing token
        //B = Number of documents not in thisCatObj, containing token
        private void computeA_C_B(Category thisCatObj, Hashtable category)
        {
            A = 0;
            C = 0;
            B = 0;

            for (Enumeration e = category.elements(); e.hasMoreElements(); )
            {
                Category catObj = (Category) e.nextElement();
                String catName = catObj.getCategoryName();

                if (catName.equals(thisCatObj.getCategoryName()))
                {
                    for (Enumeration en = catObj.getCategoryDocuments().elements(); en.hasMoreElements(); )
                    {
                        Document docObj = (Document) en.nextElement();

                        if (docObj.tokenExists(token))
                            A += 1;
                        else
                            C += 1;
                    }
                }
                else
                {
                    for (Enumeration en = catObj.getCategoryDocuments().elements(); en.hasMoreElements(); )
                    {
                        Document docObj = (Document) en.nextElement();

                        if (docObj.tokenExists(token))
                            B += 1;
                    }
                }
            }
        }

        private double lg(double x)
        {
            //java.lang.Math log(double) returns the natural logarithm
            if (x==0)
                return 0;
            else
                return (Math.log(x) / Math.log(2));
        }

    }//Inner Class MI.

}//Class MutualInfo.
